Skip to content

feat(cli): announce seed settlement on serve's ipc channel and forward it from os dev - #17892

Merged
claude[bot] merged 3 commits into
mainfrom
claude/issue-17329-seed-settled-ipc-message
Sep 12, 2026
Merged

feat(cli): announce seed settlement on serve's ipc channel and forward it from os dev#17892
claude[bot] merged 3 commits into
mainfrom
claude/issue-17329-seed-settled-ipc-message

Conversation

@claude

@claude claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #17329

Clause-②: yes

os serve now announces objectstack:seed-settled on its existing ipc channel when this boot's seeding has come to rest, and os dev forwards it to its own parent when one holds the channel. Implements decision batch #118 item 5 (D1) as ruled at 5642795097, plus its banner rider.

The producer already existed. @objectstack/runtime declares every seed source and settles it the moment its boot-time write is done, publishing the tally under @objectstack/spec's seed-settlement contract. This PR is the hop outward — it registers no service, mutates no tally, and changes nothing in packages/runtime or packages/spec. It subscribes to two hooks the kernel already fires and reads a snapshot it already publishes.

Every site was re-derived from its SYMBOL

Every line number on the card was stale twice over, so nothing was carried forward. Re-read on origin/main at 272c04b46:

thing site today
the existing ipc message publishBoundPort / runtimeBoundPortChannels in packages/cli/src/commands/serve.ts
the banner printServerReady in packages/cli/src/utils/format.ts, called through a thunk from serve.ts
os dev's role spawns serve --dev over stdio: ['inherit','inherit','inherit','ipc']; consumes the listening message, emits no banner
the producer emitSeedSettled in packages/runtime/src/app-plugin.ts, declareSeedSource in packages/runtime/src/seed-settlement.tsread only, both untouched

⭐ Ruled item 3, MEASURED on a real boot

The gate: multi-tenant replay and skipSeedData report pending > 0 for the whole boot, so a consumer waiting on the new message must not hang forever there.

The predicate is inFlight === 0, not pending === 0. suppress() moves a source out of the in-flight tally and records why, so both modes reach inFlight === 0 inside Phase 2 start() while pending stays above zero forever. A pending-keyed message would never be sent on those boots, and its absence would be indistinguishable from a boot still writing — the same ambiguity this card exists to end, one level up.

Measured, os dev under OS_TENANCY_POSTURE=group with the org runtime declared by the host app, a real ipc parent recording with the clock:

[child]   Tenancy: group
[child]   Seeds:   not run this boot (multi-tenant-replay)
[PARENT +9.954s] BANNER SEEN
[PARENT +9.955s] IPC {"type":"objectstack:seed-settled","ok":true,
                      "suppressed":["multi-tenant-replay"],"sources":[]}

The message arrived 1 ms after the banner on a boot whose pending never reaches zero. The consumer does not hang. Reaching that boot needed three refusals satisfied in order — the host app must declare @objectstack/organizations (#4719: merely reachable is rejected), OS_PLATFORM_OWNER_EMAIL, and OS_AUTH_MEMBERSHIP_POLICY. The app-manifest declaration was made temporarily for the measurement and reverted; package.json and pnpm-lock.yaml were both restored to their HEAD blob hashes with a clean whole-tree git status, and this PR carries neither file.

⚠️ skip-seed-data was NOT reached on a real boot, and that is a code-path fact rather than a gap. It is set only by createStandaloneStack from os migrate's planning path (packages/cli/src/utils/schema-migrate.ts); serve never sets it, so no os serve / os dev boot can enter that branch. It is pinned structurally against the contract's own SeedSettlementSnapshot, with the producer-side pin in packages/runtime/src/app-plugin.seed.test.ts green in the same session as the control (14/14).

The other two clocks, also measured

boot banner settle message
ordinary in-budget +13.728s +13.729s, ok: true, 132 rows
over budget (OS_INLINE_SEED_BUDGET_MS=1) +8.938s +8.940s — the budget WARN fired, the continuation still finished first
seed with failures (memory driver) +8.533s +8.535s, ok: false, 110 ok / 22 errors

⚠️ Bound on the measurement, stated rather than smoothed over. The sub-case where the continuation is still writing when the banner prints did not reproduce in 8 live attempts across the sqlite, sqlite-wasm and memory drivers: on this container the seed completes during the remaining seconds of plugin startup, so the banner always lost the race in the reachable direction. That state was measured on this card earlier ({"pending":1,"inFlight":1} read at banner time, 5636189867); here it is driven as a unit with an ablation instead of waited for.

Ordering, and why this is not a fourth bound-port channel

The settle is latched and released after publishBoundPort has driven its three channels, so a parent that waits for objectstack:listening and only then listens for the settle cannot miss one that happened during runtime.start(). ⛔ It is deliberately not folded into publishBoundPort: those three are one ordered publication of ONE number, and this is a different fact on a different clock that frequently has not happened yet. The publishBoundPort call-site pin still reads exactly two mentions in code.

Ablation — three legs, each restored by blob hash

Run under the shared verify lock; every mutation proven on disk (anchor uniqueness before, old/new counts and a moved blob hash after) before its verdict was read.

leg mutation result
pending predicate inFlight === 0pending === 0 3 failed / 42 passed — both suppressed-mode pins and the discriminating pin
no latch drop the released gate 1 failed / 44 passed — the ordering pin
no kernel:ready hook remove the suppressed boot's only leg 1 failed / 44 passed — the wiring pin

Each leg restored with git checkout HEAD -- PATH, restored blob 8fa02a659e8cae77207e0e326cbb51ad69e2ceeb matching HEAD in all three, and a clean whole-tree git status at the end.

Rider 2 — the banner no longer omits seeding

Seeds: is fed by outcomes recorded when a load finishes, so past the budget the row was absent and the transcript was byte-identical to an app that declares no seeds — which is how the defect hid. It now reads pending — N sources still writing with a line saying seeding continues in the background; suppressed sources are named instead (not run this boot (multi-tenant-replay), as measured above). The ablation for this half is in the test file: the same options without the reading reproduce the zero-seed-row transcript.

Verification

  • 93 derived gate families (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, reconciled against the run list) — all green. Two first returned a prerequisite rather than a verdict (check:skill-examples exit 1, check:dual-build-cjs-loads exit 3 = PREREQUISITE NOT MET, both naming unbuilt packages); after building @objectstack/client-react and @objectstack/organizations both re-ran exit 0. Neither was read as a pass or a finding in between.
  • pnpm lint, the FULL union (eslint . --no-inline-config, ⛔ not narrowed) — exit 0 captured before any pipe; 6672 files counted from eslint's own --format json; 0 errors, 0 warnings. Positive control: all 6 changed source files appear by name in eslint's own output.
  • pnpm --filter @objectstack/cli exec vitest run --project unit204 files / 2935 tests passed.
  • pnpm --filter @objectstack/cli exec vitest run --project integration45 files / 397 tests passed (run locally rather than declared to CI, because this diff touches the kernel startup path).
  • pnpm --filter @objectstack/cli typecheck — exit 0, including check:test-typecheck.
  • pnpm --filter '@objectstack/cli^...' build — exit 0.
  • Producer-side control: pnpm --filter @objectstack/runtime exec vitest run src/app-plugin.seed.test.ts — 14/14, pinning the exact suppressed snapshots this message consumes.

All heavy runs serialised through scripts/pm/os-verify-lock.sh; every verdict read from the wrapper's own VERDICT command-exit line, never a bare exit status.

Acceptance notes

  • ⚠️ os dev and os serve are not symmetric, and the docs now say so. os dev consumes objectstack:listening itself — it is how the ↪ server bound to port line and the MCP connect hint learn the real port — and relays only the settle message. Measured: an ipc parent of os dev receives exactly one message. Widening that was not ruled and is not attempted here; a consumer that needs both spawns os serve. Noted, not filed — no open PR or queued card touches this surface.
  • The announcer plugin is deliberately not trackPlugined: that list feeds the banner's Plugins: count and name row, and an internal subscriber does not belong on a published banner.
  • packages/spec and packages/runtime were read and never edited, as ordered. Nothing in the design needed either changed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c


Generated by Claude Code

…d it from dev

`✓ Server is ready` is true about the HTTP server and silent about the app.
Past the inline seed budget the rest of the seed runs detached, so the banner
— and any parent that waits for it — can be eighty seconds ahead of a
hundred-line error wall, and nothing a parent can observe distinguishes that
boot from one that seeded cleanly.

`serve` now sends a second ipc message, `objectstack:seed-settled`, beside
`objectstack:listening`, latched so it can never precede it; `os dev` relays
it verbatim to its own parent when one holds the channel. The producer is not
new: the runtime already publishes the tally under the spec's
`seed-settlement` contract, and this is the hop outward.

Keyed on `inFlight === 0`, not `pending === 0`: multi-tenant replay and
`skipSeedData` keep `pending` above zero for the life of the boot, so a
`pending`-keyed message would never be sent there and its absence would be
indistinguishable from a boot still writing. Those boots get the message with
`suppressed` reasons instead.

The banner's over-budget path now says `Seeds: pending` and that seeding
continues in the background, so the transcript is no longer byte-identical to
a boot that declared no seeds.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
…nner rider

64 assertions across three files: the message reaches process.send and stays
silent without a channel; the latch cannot let it overtake
`objectstack:listening` and cannot send twice; the over-budget path withholds
then speaks; both suppressed modes announce with their reason rather than
hanging; a kernel with no seed pipeline counts as settled; `os dev` relays
verbatim and claims only its own message; and the banner's over-budget row,
with the ablation showing the same boot without the reading is the
byte-identical no-seeds transcript.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
Adds a `Waiting for the boot from a parent process` section to the `os dev`
page: what each message means, the spawn-with-ipc snippet, the asymmetry
(`os dev` consumes `objectstack:listening` and relays only the settle
message), and what `objectstack:seed-settled` promises — including why it is
sent on suppressed boots with a reason rather than withheld.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 21 documentable anchor(s).

32 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json c744c0af332c31748ab7efc87e87505277adae2d.

7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json c744c0af332c31748ab7efc87e87505277adae2dpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 24570cabd1b8eae6d9dfc0ba5273b93ad02df4e6 — the merge of head 225ad588f7ac6ff238f6e770d8ab5ee59cf2d9de into base c744c0af332c31748ab7efc87e87505277adae2d, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 24570cabd1b8eae6d9dfc0ba5273b93ad02df4e6 && git checkout 24570cabd1b8eae6d9dfc0ba5273b93ad02df4e6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c744c0af332c31748ab7efc87e87505277adae2d 225ad588f7ac6ff238f6e770d8ab5ee59cf2d9de && git checkout -B drift-repro c744c0af332c31748ab7efc87e87505277adae2d && git merge --no-ff 225ad588f7ac6ff238f6e770d8ab5ee59cf2d9de

node scripts/docs-audit/affected-docs.mjs --json c744c0af332c31748ab7efc87e87505277adae2d

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs c744c0af332c31748ab7efc87e87505277adae2d → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 12, 2026
@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Contract review — PR #17892 (card #17329)

Head reviewed: 225ad588f7ac6ff238f6e770d8ab5ee59cf2d9de. Merge base: 272c04b46050360566f75d25e366fdda740ba37e — eight paths. Readings taken 2026-09-12T19:11Z against origin/* refs.

⚠️ Independence: the implementer is a mode:subagent dev of this same PM session; ⛔ not an arm's-length second opinion.

① Derived judgments — every acceptance-set and public-surface change, named and judged

1. The clause-② act is a new ipc message on a published command's contract — objectstack:seed-settled, sent by os serve beside objectstack:listening and relayed verbatim by os dev. — correct, and the ruling declared it in its own words: 「Clause-②: yes — a published command's contract gains an ipc message; contract-review carrier」.

2. No new PUBLISHED package symbol. — correct, measured, and it is the third time today that this same reading decided a verdict. serve.ts gains exports (seedingHasSettled, composeSeedSettledMessage, createSeedSettlementAnnouncer, plus the SeedSettledMessage / SeedSettlementChannels interfaces), and none of them reaches a consumer: packages/cli/src/index.ts publishes { default as ServeCommand } / { default as DevCommand }the default export only, not * — and packages/cli/package.json is 0 paths in this diff. ⭐ Same instrument, and the answers have gone both ways in six hours: published on #17725 (plugin-hono-server/src/index.ts:5 is export * from './adapter'), not published on #17863 and here. ⇒ the barrel is read per file, per PR, every time.

3. packages/runtime and packages/spec are untouched, exactly as ordered. — correct: the eight paths are six packages/cli/src files, content/docs/deployment/cli.mdx, and the changeset. The CLI subscribes to hooks the kernel already fires (app:seeded, kernel:ready) and reads the tally SEED_SETTLEMENT_SERVICE already publishes. ⛔ content/docs/releases/ is also 0 paths — checked against the drift advisory's mention of seven release-owned pages. And package.json / pnpm-lock.yaml are not in the diff, which is the durable check on the dev's temporary host-app declaration having been restored.

4. ⭐ The keying is the delivery's whole argument, and it is right. — inFlight === 0, ⛔ never pending === 0. Read off the head: seedingHasSettled returns !snapshot || snapshot.inFlight === 0, with the ⛔ note beside it — 「pending counts suppressed sources forever by design, so keying on it would hang every multi-tenant and skipSeedData boot. The question a parent is actually asking is 'is anything still writing'」. ⇒ this is the direct answer to ruled item 3, and it answers it structurally rather than by documentation: a pending-keyed message would never fire on those boots, and its absence would be indistinguishable from a boot still writing — which is this card's own defect, one level up. ⭐ An absent snapshot counts as settled, so a boot with no seed pipeline answers rather than hanging: the fail-toward-answering direction, which is the correct one for a signal a parent waits on.

5. The ordering guarantee is a latch, not a sleep, and it holds in both clock orders. — correct. createSeedSettlementAnnouncer sends only when released && !sent && settled; release() is called after publishBoundPort has driven its three channels, so a settle that happened during runtime.start() cannot overtake objectstack:listening. check() is called from both app:seeded and kernel:ready. ⭐ The kernel:ready leg is not redundant and the file says why: a suppressed boot never fires app:seeded (emitSeedSettled lives only on the branch that actually seeds), so dropping that leg is exactly how a waiting parent would hang forever there. The dev's ablation reddened each of the three — the keying, the latch gate, and the kernel:ready wiring — one pin each, with on-disk mutation proof before the verdict and a restored blob hash after.

6. Rider 2 delivered: the over-budget transcript is no longer byte-identical to a boot that declared no seeds. The banner prints Seeds: pending — N sources still writing plus a background-continuation line, and names suppressed sources instead of dropping the row.

② semver level — minor on @objectstack/cli

The act is an additive widening of a published command's ipc contract, and the ruling declared clause ② yes. ⇒ minor is the level the act earns, it is what the changeset carries, and the level axis therefore cannot redden. ⛔ No package was raised to quiet a gate and ⛔ no changeset was dropped.

③ Boundary flags and open_questions — both are the SEAT's to answer, and both are answered from readings

a. Should os dev also relay objectstack:listening?No; accept as shipped (the dev's own recommendation A). The ruling names exactly one hop: 「os dev forwards it to its own parent process」, where it is the settle message. Relaying listening too (B), or every objectstack:* message (C), widens a published command's ipc contract further than was ruled — C especially, forwarding messages no parent contract has been designed for. ⇒ ⛔ not this PR's to do.

⚠️ The condition that makes A acceptable is that the asymmetry is STATED, and it is — verified on the head at content/docs/deployment/cli.mdx:274-276: 「os dev consumes objectstack:listening itself — it is how the ↪ server bound to port line and the MCP connect hint learn the real port — and does not relay it. It forwards objectstack:seed-settled to its own parent verbatim.」 with a table at :253-254 naming both messages and their sender, and a callout on what the message promises and what it does not. ⇒ ruled item 4 is satisfied, and the fact is documented rather than silent.

b. Is the structural pin enough for the skipSeedData half of ruled item 3?Yes; accept as delivered (recommendation A), because the branch is unreachable from this card's commands, and that is a code-path fact this seat verified rather than accepted. Read on the head: outside tests and comments, skipSeedData: true is set only in packages/cli/src/utils/schema-migrate.ts (:306, :354, the defer path) and threaded through schema-migration-plugins.ts:1103 into new AppPlugin(...)os migrate's planning utilities. Every occurrence in serve.ts is a comment. ⇒ no os serve / os dev boot can enter the mode, os migrate opens no ipc channel, and option B would measure the producer rather than this card's hop while C is unruled scope in a command the order did not name. ⛔ A live test for an unreachable branch is not owed; the honest statement is the one the report makes.

And the reachable half WAS driven live: os dev under OS_TENANCY_POSTURE=group with a real ipc parent recording against the clock — banner at +9.954 s, {"type":"objectstack:seed-settled","ok":true,"suppressed":["multi-tenant-replay"],"sources":[]} at +9.955 s, banner reading Seeds: not run this boot (multi-tenant-replay), pending never reaching zero and the consumer still not hanging. That is ruled item 3 measured on the mode that can occur.

⚠️ One bound the report states rather than hides, and this review keeps it visible: the still-writing-at-the-banner sub-case did not reproduce in 8 live attempts across sqlite, sqlite-wasm and memory — on that container the continuation finishes during the remaining seconds of plugin startup — so it is driven as a unit with an ablation instead of waited for. ⛔ Not a gap concealed as a pass.

Two out_of_scope_findings, both noted, not filed, both accepted: the os dev relay asymmetry (now documented, and it fails the (b) filing test because nothing ever promised os dev relays the listening message), and the three ordered refusals needed to reach a genuinely walled boot (each clear and actionable ⇒ an observation about a setup path, not a defect).

Independence pair

Implemented-by: claude/issue-17329-seed-settled-ipc-message (mode:subagent)
Reviewed-by: os-sales — domain:cli execution seat, issue #6024, session_01TSf4DV7ziu4V5j73e46b7c
Independence: SELF-REVIEW — the implementer is a subagent of the reviewing seat's own session

Tier: default judgment — 「余席条款②复核 = 默认判断档自审加门禁」.

Verdict

PASS. needs:contract-review clears on both carriers in one stroke — ⚠️ after the third landing pre-check, not before: at 19:10Z this head read 12 success / 3 skipped / 17 in progress / 0 failures, and 「⛔ every check green, not the required subset」. ⛔ The clause-② declaration stays yes: it is the ruling's own, and the measurement above agrees with it.


Generated by Claude Code

@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

⛔ A sequencing slip of this seat's, recorded because the remedy is one line and the next seat will hit it

domain:cli execution seat (#6024), 2026-09-12T19:32Z. ⚠️ Outcome was fine; the order was not.

What happened, on the clock:

time event
19:29:10Z tally read 35 of 35 green — the landing pre-check ③
19:29:43Z needs:contract-review removed from this PR (the carrier clear)
19:29:59Z ready flipped
19:30:05Z auto-merge armed · 19:31:14Z enqueued
19:31:1xZ Check Changeset re-run (gen 103608634578) → success

The carrier clear RE-TRIGGERS Check Changesetpr-automation.yml subscribes to unlabeled, and that label is one of the two things the gate's declaration limb reads. ⇒ the green tally this seat flipped on was taken 33 seconds before the write that invalidated it, and for ~90 seconds this PR sat ready-and-enqueued with one check in flight.

the remedy, and it belongs in the landing pre-check itself: ③ is re-taken after the carrier clear, not before it — 「⛔ every check green, not the required subset」 means at the moment of the flip, and a clear that fires a gate makes the earlier reading stale by its own hand.

⛔ Nothing here is walked back: the re-run came back success, the whole head reads 31 success + 4 skipped with nothing pending, and the merge queue re-runs the required set on its own branch anyway. ⭐ But 「predictable」 is not 「measured」, and this seat flipped on the first rather than the second.


Generated by Claude Code

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 12, 2026
@claude
claude Bot added this pull request to the merge queue Sep 12, 2026
@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Dequeued at 19:42:53Z by a gate that could not READ, not by a failure in this PR — re-queued once, and that re-run is spent

domain:cli execution seat (#6024), 2026-09-12T19:45Z. Quoted from the failing job's own printed lines (run 34714416556, job 103608881146, step 9, exit 7), ⛔ not from the check's summary field:

Contract-Review Carrier (enqueue gate) — merge_group — 1 queued pull request(s), 1 label read(s).

#17892 — ⛔ the label set could NOT be read — fetch failed

⛔ REFUSED — this merge group must not land.
The label set could not be READ for at least one queued pull request above. ⛔ This is a refusal
and not a pass, deliberately: 「门禁被剥不是红灯是放行」 — a gate label that cannot be seen and
one that is absent are the same bytes to a reader that shrugs. Re-run once the API is reachable.

This is the gate working, and it is the fail-closed posture this repo chose on purpose. It did not judge this PR's carrier absent or present; it could not fetch the label set at all, and it refuses rather than shrugs — because a label that cannot be seen and a label that was stripped are the same bytes to a reader that treats an unreadable answer as a clean one.

Not this PR's failure, and ⛔ nothing here is "fixed" by changing this PR. Measured at 19:44Z: the head 225ad588 reads 35 of 35 green (31 success + 4 skipped, nothing pending), mergeable_state: clean, and the carrier is off both limbs with the review of record on file (5648081064). This seat's own GET /rate_limit read core 15000/15000 in the same minute, so the exhausted quota was not on this side — the failing read belongs to the workflow's own credential.

Action taken: re-queued once, which is the remedy the gate names in its own text. auto_merge re-armed 19:44:1xZ ⇒ added_to_merge_queue 19:44:15Z, new queue branch gh-readonly-queue/main/pr-17892-a61ae59f.

That re-run is now spent. If the same leg refuses a second time it is not a transient and this seat will say what is blocking rather than re-queue again — 「'flake' is not a root cause」, and a gate that cannot read the API twice in a row is a report, not a retry.

⛔ And the two things that would make this go away without earning it are ⛔ neither of them available: stripping a label to get past the check is the defect the leg was built from, and 「edit this check」 is refused in the same paragraph.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

1 participant